﻿using System;
namespace DataProcess.Special.List
{
    /// <summary>
    /// 节点位置
    /// </summary>
    public enum TreeNodePosition
    {
        LeftChild, RightChild
    }
    /// <summary>
    /// 二叉树节点
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class BinaryTreeNode<T>
    {
        protected T data;
        protected BinaryTreeNode<T> leftchild, rightchild, parent;

        /// <summary>
        /// 处理节点方法
        /// </summary>
        /// <param name="parent">父节点</param>
        /// <param name="changed">处理的子节点</param>
        /// <param name="pos">位于父节点的位置</param>
        public delegate void NodeFunction(BinaryTreeNode<T> parent, BinaryTreeNode<T> changed, TreeNodePosition pos);

        /// <summary>
        /// 当节点被处理时的事件
        /// </summary>
        public event NodeFunction OnNodeChanged;

        /// <summary>
        /// 节点值
        /// </summary>
        public T Value
        {
            get => data;
            set => data = value;
        }
        /// <summary>
        /// 父节点
        /// </summary>
        public BinaryTreeNode<T> Parent => parent;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="d">节点值</param>
        public BinaryTreeNode(T d)
        {
            Value = d;
        }
        public BinaryTreeNode()
        {
        }
        /// <summary>
        /// 左子节点
        /// </summary>
        public BinaryTreeNode<T> NextLeftChild
        {
            get => leftchild;
            set
            {
                leftchild = value;
                leftchild.parent = this;
                if (OnNodeChanged != null)
                {
                    OnNodeChanged(this, leftchild, TreeNodePosition.LeftChild);
                }

            }
        }
        /// <summary>
        /// 右子节点
        /// </summary>
        public BinaryTreeNode<T> NextRightChild
        {
            get => rightchild;
            set
            {
                rightchild = value;
                rightchild.parent = this;
                if (OnNodeChanged != null)
                {
                    OnNodeChanged(this, rightchild, TreeNodePosition.RightChild);
                }
            }
        }
        /// <summary>
        /// 重连节点
        /// </summary>
        /// <param name="parent">父节点</param>
        /// <param name="child">子节点</param>
        /// <param name="pos">子节点置于父节点的位置</param>
        /// <param name="force">是否强制连接（即忽视父节点的对应位置必须为空，且子节点的父节点为空）</param>
        public static void ReConnect(BinaryTreeNode<T> parent, BinaryTreeNode<T> child, TreeNodePosition pos, bool force = false)
        {

            if (parent == null)
            {
                throw new Exception("空父节点");
            }
            if (pos == TreeNodePosition.LeftChild)
            {
                if (force || parent.NextLeftChild == null && child.parent == null)
                {
                    parent.NextLeftChild = child;
                    child.parent = parent;
                    if (parent.OnNodeChanged != null)
                    {
                        parent.OnNodeChanged(parent, parent.NextLeftChild, TreeNodePosition.LeftChild);
                    }
                }
            }
            else
            {
                if (force || parent.NextRightChild == null && child.parent == null)
                {
                    parent.NextRightChild = child;
                    child.parent = parent;
                    if (parent.OnNodeChanged != null)
                    {
                        parent.OnNodeChanged(parent, parent.NextRightChild, TreeNodePosition.RightChild);
                    }
                }
            }


        }

        public static implicit operator T(BinaryTreeNode<T> node)
        {
            return node.Value;
        }
        public static explicit operator BinaryTreeNode<T>(T d)
        {
            return new BinaryTreeNode<T>(d);
        }
        /// <summary>
        /// 删除指定节点的所有子节点
        /// </summary>
        /// <param name="node">指定节点</param>
        public static void DeleteNodeChildren(BinaryTreeNode<T> node)
        {
            BinaryTreeNode<T> l = node.NextLeftChild;
            BinaryTreeNode<T> r = node.NextRightChild;
            if (l != null)
            {
                DeleteNodeChildren(l);
            }
            if (r != null)
            {
                DeleteNodeChildren(r);
            }
            node.leftchild = null;
            node.rightchild = null;
        }
    }
}